[iOS 8] PhotoKit 4 – Photos Framework – モデルオブジェクトのコンテンツの編集
はじめに
前回はモデルオブジェクトのプロパティの編集を扱いましたが、 今回はモデルオブジェクトのコンテンツ(写真やビデオの実データ)の編集を扱います。
PHAssetのコンテンツの編集手順
モデルオブジェクトのコンテンツの編集はPHAssetの場合のみ可能です。 PHAssetのコンテンツの編集手順について説明していきます。
- (void)applyFilter { NSString *AdjustmentFormatIdentifier = @"com.example.samplecode.SamplePhotosApp"; NSString *formatVersion = @"1.0"; NSString *filterName = @"CISepiaTone"; // [3] PHContentEditingInputRequestOptionsを作成、canHandleAdjustmentDataをセット PHContentEditingInputRequestOptions *options = [[PHContentEditingInputRequestOptions alloc] init]; [options setCanHandleAdjustmentData:^BOOL(PHAdjustmentData *adjustmentData) { return [adjustmentData.formatIdentifier isEqualToString:AdjustmentFormatIdentifier] && [adjustmentData.formatVersion isEqualToString:formatVersion]; }]; // [1] 編集処理がサポートされているかを問い合わせる // 引数にPHAssetEditOperationContentを指定 if ([self.asset canPerformEditOperation:PHAssetEditOperationContent]) { // [2] Assetのコンテンツ編集セッションを開始するために必要な情報をリクエスト [self.asset requestContentEditingInputWithOptions:options completionHandler:^(PHContentEditingInput *contentEditingInput, NSDictionary *info) { // [4] フルサイズのイメージを取得 NSURL *url = [contentEditingInput fullSizeImageURL]; int orientation = [contentEditingInput fullSizeImageOrientation]; CIImage *inputImage = [CIImage imageWithContentsOfURL:url options:nil]; inputImage = [inputImage imageByApplyingOrientation:orientation]; // [5] フィルターを適用、NSDataを作成 CIFilter *filter = [CIFilter filterWithName:filterName]; [filter setDefaults]; [filter setValue:inputImage forKey:kCIInputImageKey]; CIImage *outputImage = [filter outputImage]; NSData *jpegData = [outputImage aapl_jpegRepresentationWithCompressionQuality:0.9f]; // [6] PHAdjustmentDataを作成 PHAdjustmentData *adjustmentData = [[PHAdjustmentData alloc] initWithFormatIdentifier:AdjustmentFormatIdentifier formatVersion:formatVersion data:[filterName dataUsingEncoding:NSUTF8StringEncoding]]; // [7] PHContentEditingOutputを作成、指定URLにjpegファイルを書き出し PHContentEditingOutput *contentEditingOutput = [[PHContentEditingOutput alloc] initWithContentEditingInput:contentEditingInput]; [jpegData writeToURL:[contentEditingOutput renderedContentURL] atomically:YES]; [contentEditingOutput setAdjustmentData:adjustmentData]; // [8] Assetの編集を実行 [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{ PHAssetChangeRequest *request = [PHAssetChangeRequest changeRequestForAsset:self.asset]; request.contentEditingOutput = contentEditingOutput; } completionHandler:^(BOOL success, NSError *error) { if (!success) { NSLog(@"%s Error: %@", __PRETTY_FUNCTION__, error); } }]; }]; } }
[1] 編集処理がサポートされているかを問い合わせる
PHAssetのプロパティの編集を行う場合と同様に、 canPerformEditOperation:メソッドを使用して編集処理がサポートされているかをチェックします。
[2] Assetのコンテンツ編集セッションを開始するために必要な情報をリクエスト
次にPHAssetのrequestContentEditingInputWithOptions:completionHandler:メソッドを使用して PHAssetの編集セッションを開始するために必要な情報をリクエストします。
option引数には、[4]で作成するPHContentEditingInputRequestOptionsを渡します。
completionHandler引数に渡すblockは、編集用の情報が用意出来た時に呼ばれるので、 その時に行う処理を記述します。 blockの1つめの引数はPHContentEditingInputオブジェクトになっていて、 このオブジェクトを使用してコンテンツの編集に必要なデータ(Assetのプロパティやコンテンツ自体のURLなど)を取得できます。 2つめの引数のNSDictionaryにはリクエストのステートの状態が格納されます。
[3] PHContentEditingInputRequestOptionsを作成
PHContentEditingInputRequestOptionsのcanHandleAdjustmentDataプロパティにblockをセットしています。 このblockはPHAssetに対する以前の編集を続行できるかどうかを判断する必要がある時によばれます。
このblockでYESをした場合、編集用のオリジナルデータが提供され、 以前行なった編集を再現したり、加工を加えたりすることができます。
NOを返した場合は、以前行なった編集がレンダリングされたデータが提供されます。
PHAdjustmentDataについては[6]で説明します。
[4] フルサイズのイメージを取得
PHContentEditingInputのメソッドを使用して画像データを取得し、 CIImageオブジェクトを作成します。
[5] フィルターを適用、NSDataを作成
Core Imageのフィルターを適用し、NSDataを作成します。
[6] PHAdjustmentDataを作成
PHAdjustmentDataオブジェクトの作成を行います。 PHAdjustmentDataオブジェクトはAssetを編集したAppやExtensionが作成するオブジェクトで、 編集を再現するための「レシピ」になります。 PHAdjustmentDataオブジェクトのフォーマットはAppやExtension側で定義するもので、 例えば、フィルターアプリなら、ユーザーに選択されたフィルタやパラメータを保存しておきます。 あなたが定義したPHAdjustmentDataのフォーマットを知っているアプリであれば、 PHAdjustmentDataを使用して、編集をレジュームできます。
ここでは、フィルタ名の文字列を保存するようにしています。
[3]で「以前の編集を続行できるかどうかを判断する処理」について触れましたが、 [3]のcanHandleAdjustmentDataプロパティのblock内では、 ここで作成するPHAdjustmentDataをチェックして処理を分けています。
[7] PHContentEditingOutputを作成、指定URLにjpegファイルを書き出し
Assetのコンテンツの編集結果を表すオブジェクトであるPHContentEditingOutputオブジェクトを作成し、 PHContentEditingOutputオブジェクトのrenderedContentURLプロバティが示す場所にjpegファイルを書き出し、 [6]で作成したPHAdjustmentDataオブジェクトをセットしています。
[9] Assetの編集を実行
Assetのコンテンツの編集を実行します。 PHAssetのプロパティの編集を行う場合と同様に、 PHPhotoLibraryオブジェクトのperformChanges:completionHandler:メソッドを使用します。
1つ目の引数のblock内に編集処理を記述します。 PHAssetChangeRequestを作成し、contentEditingOutputプロパティに[8]で作成したPHContentEditingOutputオブジェクトをセットします。
2つめのblockに処理完了時の処理を記述します。
確認ダイアログ
Assetのプロパティの編集時には表示されありませんでしたが、コンテンツの編集の場合は 編集処理を実行したタイミングで以下のようなダイアログが表示されます。
「変更」を選択した場合
「変更」 を選択すると、変更が実行されます。
「許可しない」を選択した場合
「許可しない」 を選択すると、completionHandlerのblockの引数にNSErrorオブジェクトが渡されます。 (NSErrorオブジェクトのlocalizedDescriptionは「The operation couldn’t be completed. (Cocoa error -1.)」)
まとめ
今回はモデルオブジェクトのコンテンツ自体の編集について説明しました。プロパティの編集に比べて手順は多くなりますが、比較的簡単にコンテンツ自体を編集することができます。
次回はモデルオブジェクトの削除を扱います。
参考資料
- Photos Framework Reference
- Introducing the Photos Frameworks - WWDC 2014 Session Videos
本シリーズの記事一覧
- [iOS 8] PhotoKit 1 – Photos Frameworkの概要
- [iOS 8] PhotoKit 2 – Photos Framework – モデルオブジェクトの取得
- [iOS 8] PhotoKit 3 – Photos Framework – モデルオブジェクトのプロパティの編集
- [iOS 8] PhotoKit 4 – Photos Framework – モデルオブジェクトのコンテンツの編集
- [iOS 8] PhotoKit 5 – Photos Framework – モデルオブジェクトの削除
- [iOS 8] PhotoKit 6 – Photos Framework – モデルの変更のハンドリングとコンテンツ編集のrevert
- [iOS 8] PhotoKit 7 – Photos Framework – フォトライブラリへのアクセス許可を得る
- [iOS 8] PhotoKit 8 - UIImagePickerControllerとPhotos Frameworkを組み合わせて使う
- [iOS 8] PhotoKit 9 – Photo Editing Extensionの概要
- [iOS 8] PhotoKit 10 – Photo Editing Extensionの実装 (前篇)
- [iOS 8] PhotoKit 11 – Photo Editing Extensionの実装 (後篇)